package com.db4o.servlet;

import java.io.File;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;

import com.db4o.*;

/**
 * db4o servlet source code.
 * <br><br>Use the methods in the @link{Db4oServlet} class.
 */
public class ServletDaemon {
    public final static String ATTRIBUTENAME = "Db4oServletDaemon";
    private final static String TERMINATE_db4o_SESSION = "TERMINATE_db4o_SESSION";
    private final ClassLoader i_classLoader;
    private final List i_files = new ArrayList();

    private ServletDaemon(ServletContext context, ClassLoader sessionLoader) {
        i_classLoader = sessionLoader;
        context.setAttribute(ATTRIBUTENAME, this);
    }

    /**
     * is used to shut down a db4o session if class exchanges produce 
     * multiple ClassLoader namespaces.
     * <br><br>This method is only exposed publically for compatibility with 
     * <code>java.lang.Object#equals(Object)</code>.<br><br>
     */
    public boolean equals(Object obj) {
        if (obj instanceof String) {
            if (obj.equals(TERMINATE_db4o_SESSION)) {
                terminate();
                return false;
            }
        }
        return super.equals(obj);
    }

    synchronized ObjectContainer objectContainer(
        HttpSession session,
        String filename,
        boolean shareTransaction) {
    	
    	String path = session.getServletContext().getInitParameter("dbpath");
    	File f = new File(path);        
    	if (!f.exists())  f.mkdirs();        
    	
    	filename = path + "/" + filename;
        ServletFile file = null;
        synchronized (i_files) {
            Iterator i = i_files.iterator();
            while (i.hasNext()) {
                ServletFile existing = (ServletFile) i.next();
                if (filename.equals(existing.i_filename)) {
                    file = existing;
                    break;
                }
            }
            if (file == null) {
                file = new ServletFile(filename, shareTransaction);
                i_files.add(file);
            } else {
                if (file.i_shareTransaction != shareTransaction) {
                    throw new IllegalStateException("An ObjectContainer file can not be accessed in sharedTransaction and singleTransaction mode at the same time.");
                }
            }
        }
        return file.objectContainer(session);
    }

    public void terminate() {
        synchronized (i_files) {
            Iterator i = i_files.iterator();
            while (i.hasNext()) {
                ((ServletFile) i.next()).terminate();
            }
            i_files.clear();
        }
    }

    static synchronized ServletDaemon servletDaemon(
        javax.servlet.ServletContext context,
        javax.servlet.http.HttpSession session) {
        boolean killDaemon = false;
        ClassLoader sessionLoader = ((Object) session).getClass().getClassLoader();
        ServletDaemon daemon = (ServletDaemon) context.getAttribute(ServletDaemon.ATTRIBUTENAME);
        if (daemon != null) {
            if (!(daemon instanceof ServletDaemon)) {
                killDaemon = true;
            } else {
                if (((ServletDaemon) daemon).i_classLoader != sessionLoader) {
                    killDaemon = true;
                }
            }
            if (killDaemon) {
                daemon.equals(ServletDaemon.TERMINATE_db4o_SESSION);
                context.removeAttribute(ServletDaemon.ATTRIBUTENAME);
                daemon = null;
            }
        }
        if (daemon == null) {
            daemon = new ServletDaemon(context, sessionLoader);
        }
        return daemon;
    }

}
